home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xconq / mplay.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  36KB  |  1,307 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. #pragma comment(exestr, "@(#) mplay.c 12.1 95/05/09 ")
  6.  
  7. /* RCS $Header: mplay.c,v 1.3 88/07/20 16:07:59 shebs Exp $ */
  8.  
  9. /* This file implements all of machine strategy.  Not much room for fancy */
  10. /* tricks, just solid basic play.  The code emphasizes avoidance of mistakes */
  11. /* instead of strategic brilliance, so machine behavior is akin to bulldozer */
  12. /* plodding.  Nevertheless, bulldozers can be very effective when they */
  13. /* outnumber the human players... */
  14.  
  15. /* It is also very important to prevent infinite loops, so no action of the */
  16. /* machine player is 100% certain. */
  17.  
  18. #include "config.h"
  19. #include "misc.h"
  20. #include "dir.h"
  21. #include "period.h"
  22. #include "side.h"
  23. #include "unit.h"
  24. #include "map.h"
  25. #include "global.h"
  26.  
  27. /* Maximum number of unit groups that can be maintained.  Need groups for */
  28. /* both offense and defense. */
  29.  
  30. #define MAXGROUPS 80
  31.  
  32. /* the non-group */
  33.  
  34. #define NOGROUP 0
  35.  
  36. /* Goals for both groups and individuals. */
  37.  
  38. #define NOGOAL 0
  39. #define DRIFT 1
  40. #define HITTARGET 2
  41. #define CAPTARGET 3
  42. #define BESIEGE 4
  43. #define OCCUPYHEX 5
  44. #define EXPLORE 6
  45. #define DEFEND 7
  46. #define LOAD 8
  47. #define APPROACH 9
  48. #define RELOAD 10
  49.  
  50. /* Groups organize machine player activity at the multiple-unit level. */
  51.  
  52. typedef struct a_group {
  53.     short goal;                 /* the intended purpose of the group */
  54.     short priority;             /* how important the group is */
  55.     short x, y;                 /* a relevant location */
  56.     short etype;                /* type of a unit there (or NOTHING) */
  57.     short area;                 /* radius of relevance of group activity */
  58.     short member[MAXUTYPES];    /* number of each type in group */
  59.     short need[MAXUTYPES];      /* what group wants but doesn't have */
  60. } Group;
  61.  
  62. /* This structure is where machine sides keep all the plans and planning */
  63. /* related data. */
  64. /* Group 0 is never actually used (a sort of a dummy for various purposes). */
  65.  
  66. typedef struct a_plan {
  67.     short estimate[MAXSIDES][MAXUTYPES];  /* estimated numbers of units */
  68.     short allies[MAXSIDES][MAXUTYPES];  /* strength of other alliances */
  69.     short cx, cy;               /* "centroid" of all our units */
  70.     short lastreplan;           /* last turn we rechecked the plans */
  71.     short demand[MAXUTYPES];    /* worth of each utype w.r.t. strategy */
  72.     Group group[MAXGROUPS];     /* all the groups that can be formed */
  73. } Plan;
  74.  
  75. /* Encapsulate some pointer-chasing and casting messiness. */
  76.  
  77. #define side_plan(s) ((Plan *) (s)->plan)
  78.  
  79. /* Malloced integer array accessors and modifers. */
  80.  
  81. #define aref(m,x,y) ((m)[(x)+world.width*(y)])
  82.  
  83. #define aset(m,x,y,v) ((m)[(x)+world.width*(y)] = (v))
  84.  
  85. int evaluate_hex(), maximize_worth();
  86.  
  87. char groupbuf[BUFSIZE];         /* buffer for group debugging print */
  88. char shortbuf[BUFSIZE];         /* buffer for short unit description */
  89.  
  90. /* General collections of numbers used by all machine players. */
  91.  
  92. int fraction[MAXTTYPES];        /* percentages of terrain types in world */
  93. int bhw[MAXUTYPES][MAXUTYPES];  /* basic worth for hitting */
  94. int bcw[MAXUTYPES][MAXUTYPES];  /* basic worth for capturing */
  95. int maxoccupant[MAXUTYPES];     /* total capacity of a transport */
  96. int *localworth;                /* for evaluation of nearby hexes */
  97.  
  98. int bestworth = -10000, bestx, besty;
  99.  
  100. Unit *munit;                    /* Unit being decided about */
  101.  
  102. Side *mside;                    /* Side whose unit is being decided about */
  103.  
  104. /* List out data about a group (very compactly). */
  105.  
  106. char *
  107. group_desig(plan, g)
  108. Plan *plan;
  109. int g;
  110. {
  111.     int e = plan->group[g].etype;
  112.  
  113.     sprintf(groupbuf, "group %d goal %d pri %d ->%d,%d %d (%c)",
  114.         g, plan->group[g].goal, plan->group[g].priority,
  115.         plan->group[g].x, plan->group[g].y, plan->group[g].area,
  116.         (e == NOTHING ? ' ' : utypes[e].uchar));
  117.     return groupbuf;
  118. }
  119.  
  120. /* Short unreadable but greppable listing of unit. */
  121.  
  122. char *
  123. unit_desig(unit)
  124. Unit *unit;
  125. {
  126.     sprintf(shortbuf, "s%d %d %c (%d,%d)",
  127.         side_number(unit->side), unit->number, utypes[unit->type].uchar,
  128.         unit->x, unit->y);
  129.     return shortbuf;
  130. }
  131.  
  132. /* Init used by all machine players.  Precompute useful information */
  133. /* relating to unit types in general, and that usually gets referenced */
  134. /* in inner loops. */
  135.  
  136. init_mplayers()
  137. {
  138.     int u, u2, t, g;
  139.     Side *side, *side2;
  140.  
  141.     localworth = (int *) malloc(world.width*world.height*sizeof(int));
  142.     for_all_terrain_types(t) {
  143.     fraction[t] = ((ttypes[t].maxalt - ttypes[t].minalt) *
  144.                (ttypes[t].maxwet - ttypes[t].minwet)) / 100;
  145.     }
  146.     for_all_unit_types(u) {
  147.     maxoccupant[u] = 0;
  148.     for_all_unit_types(u2) {
  149.         bhw[u][u2] = basic_hit_worth(u, u2);
  150.         bcw[u][u2] = basic_capture_worth(u, u2);
  151.         maxoccupant[u] += utypes[u].capacity[u2];
  152.     }
  153.     }
  154.     /* tell us about how things rated */
  155.     if (Debug) {
  156.     for_all_terrain_types(t) {
  157.         printf("%3d%% ", fraction[t]);
  158.     }
  159.     printf("\n\n");
  160.     for_all_unit_types(u) {
  161.         for_all_unit_types(u2) printf("%5d", bhw[u][u2]);
  162.         printf("\n");
  163.     }
  164.     printf("\n");
  165.     for_all_unit_types(u) {
  166.         for_all_unit_types(u2) printf("%5d", bcw[u][u2]);
  167.         printf("\n");
  168.     }
  169.     printf("\n");
  170.     }
  171.     /* For all sides, because human might use "robot" option */
  172.     for_all_sides(side) {
  173.     side->plan = (long) (Plan *) malloc(sizeof(Plan));
  174.     side_plan(side)->cx = side_plan(side)->cy = 0;
  175.     for (g = 0; g < MAXGROUPS; ++g) {
  176.         side_plan(side)->group[g].goal = NOGROUP;
  177.         side_plan(side)->group[g].priority = 0;
  178.     }
  179.     side_plan(side)->lastreplan = -100;
  180.     }
  181. }
  182.  
  183. /* A crude estimate of the payoff of one unit type hitting on another type. */
  184. /* This is just for general estimation, since actual worth may depend on */
  185. /* damage already sustained, unit's goals, etc. */
  186.  
  187. basic_hit_worth(u, e)
  188. int u, e;
  189. {
  190.     int worth, anti;
  191.  
  192.     worth = utypes[u].hit[e] * min(utypes[e].hp, utypes[u].damage[e]);
  193.     if (utypes[e].hp > utypes[u].damage[e]) {
  194.     worth /= utypes[e].hp;
  195.     }
  196.     if (period.counterattack) {
  197.     anti = utypes[e].hit[u] * min(utypes[u].hp, utypes[e].damage[u]);
  198.     if (utypes[u].hp > utypes[e].damage[u]) {
  199.         anti /= utypes[u].hp;
  200.     }
  201.     }
  202.     worth -= anti;
  203.     return worth;
  204. }
  205.  
  206. /* A crude estimate of the payoff of one unit type trying to capture. */
  207.  
  208. basic_capture_worth(u, e)
  209. int u, e;
  210. {
  211.     int worth = 0, anti = 0;
  212.  
  213.     if (could_capture(u, e)) {
  214.     worth += utypes[u].capture[e] * utypes[u].hp;
  215.     }
  216.     return worth;
  217. }
  218.  
  219. /* At the beginning of each turn, can make plans and review the situation. */
  220. /* This should be frequent at first, but rather expensive to do always, */
  221. /* so only some chance of doing it on a random turn. */
  222.  
  223. init_machine_turn(side)
  224. Side *side;
  225. {
  226.     if (global.time < 20 || probability(30)) make_strategy(side);
  227.     if (global.time < 20 || probability(50)) review_groups(side);
  228.     if (global.time > 20 || probability(20)) decide_resignation(side);
  229. }
  230.  
  231. /* Strategy is based on a study of the entire world map, looking for */
  232. /* duties and opportunities. */
  233.  
  234. make_strategy(side)
  235. Side *side;
  236. {
  237.     int u, i, g, x, y, view, etype, x0, x1, x2, y1, y2, choice;
  238.     int pri, sumx = 0, sumy = 0, n = 0;
  239.     Plan *plan = side_plan(side);
  240.     Side *side2, *eside;
  241.  
  242.     for_all_sides(side2) {
  243.     for_all_unit_types(u) {
  244.         plan->estimate[side_number(side2)][u] = 0;
  245.     }
  246.     }
  247.     for (y = 0; y < world.height; ++y) {
  248.     for (x = 0; x < world.width; ++x) {
  249.         view = side_view(side, x, y);
  250.         if (view != EMPTY && view != UNSEEN) {
  251.         if (side == side_n(vside(view))) {
  252.             sumx += x;  sumy += y;  n++;
  253.         }
  254.         }
  255.     }
  256.     }
  257.     if (n > 0) {
  258.     plan->cx = sumx / n;  plan->cy = sumy / n;
  259.     }
  260.     for (y = 0; y < world.height; ++y) {
  261.     for (x = 0; x < world.width; ++x) {
  262.         view = side_view(side, x, y);
  263.         if (view != EMPTY && view != UNSEEN) {
  264.         eside = side_n(vside(view));
  265.         etype = vtype(view);
  266.         if (!allied_side(side, eside)) {
  267.             choice = attack_type(etype);
  268.             if (eside == NULL && choice == HITTARGET) {
  269.             /* uncapturable neutrals are basically dull */
  270.             } else if (!find_group(side, choice, x, y)) {
  271.             pri = 100 - (100 * distance(x, y, plan->cx, plan->cy))
  272.                          / world.width;
  273.             form_group(side, choice, pri+1, x, y, 0, etype);
  274.             }
  275.         } else {
  276.             if (!mobile(etype) && !defended(side, x, y)) {
  277.             form_group(side, DEFEND, 1, x, y, 3, NOTHING);
  278.             }
  279.         }
  280.         if (eside) plan->estimate[side_number(eside)][etype]++;
  281.         }
  282.     }
  283.     }
  284.     if (!world.known) {
  285.     if (!find_group(side, EXPLORE, -1, -1)) {
  286.         x0 = 0 + random(world.width/3);
  287.         x1 = world.width/3 + random(world.width/3);
  288.         x2 = (2*world.width)/3 + random(world.width/3);
  289.         y1 = 0 + random(world.height/3);
  290.         y2 = (2*world.height)/3 + random(world.height/3);
  291.         form_group(side, EXPLORE, 1, x0, y1, 3, NOTHING);
  292.         form_group(side, EXPLORE, 1, x1, y1, 3, NOTHING);
  293.         form_group(side, EXPLORE, 1, x2, y1, 3, NOTHING);
  294.         form_group(side, EXPLORE, 1, x0, y2, 3, NOTHING);
  295.         form_group(side, EXPLORE, 1, x1, y2, 3, NOTHING);
  296.         form_group(side, EXPLORE, 1, x2, y2, 3, NOTHING);
  297.     }
  298.     }
  299.     /* should form a hex occupation group if hex mentioned in win/lose */
  300. }
  301.  
  302. /* Decides if unit has nothing covering it. */
  303.  
  304. defended(side, x, y)
  305. Side *side;
  306. int x, y;
  307. {
  308.     int g;
  309.     Plan *plan = side_plan(side);
  310.  
  311.     for (g = 1; g < MAXGROUPS; ++g) {
  312.     if ((plan->group[g].goal == DEFEND) &&
  313.         (distance(x, y, plan->group[g].x, plan->group[g].y) <=
  314.          plan->group[g].area))
  315.         return TRUE;
  316.     }
  317.     return FALSE;
  318. }
  319.  
  320. /* Review existing groups and get rid of useless ones.  Start by recomputing */
  321. /* the members, since we don't update when units die or get transferred. */
  322. /* (Since at beginning of turn, all units known to be alive.) */
  323.  
  324. review_groups(side)
  325. Side *side;
  326. {
  327.     int g, u, u2, e, view, ideal;
  328.     Plan *plan = side_plan(side);
  329.     Group *group;
  330.     Unit *unit;
  331.  
  332.     for_all_unit_types(u) {
  333.     plan->demand[u] = 0;
  334.     }
  335.     for (g = 1; g < MAXGROUPS; ++g) {
  336.     for_all_unit_types(u) {
  337.         plan->group[g].member[u] = 0;
  338.         plan->group[g].need[u] = 0;
  339.     }
  340.     }
  341.     for_all_units(unit) {
  342.     if (unit->side == side) plan->group[unit->group].member[unit->type]++;
  343.     }
  344.     for (g = 1; g < MAXGROUPS; ++g) {
  345.     group = &(plan->group[g]);
  346.     switch (group->goal) {
  347.     case NOGROUP:
  348.         /* a non-existent group */
  349.         break;
  350.     case HITTARGET:
  351.         view = side_view(side, group->x, group->y);
  352.         if (view == EMPTY || view == UNSEEN ||
  353.         side_n(vside(view)) == NULL ||
  354.         allied_side(side, side_n(vside(view)))) {
  355.         disband_group(side, g);
  356.         } else {
  357.         for_all_unit_types(u) {
  358.             if (could_hit(u, group->etype)) {
  359.             e = group->etype;
  360.             if (utypes[u].damage[e] > 0) {
  361.                 ideal = (2 * utypes[e].hp * utypes[u].hit[e]) /
  362.                 utypes[u].damage[e];
  363.             } else {
  364.                 ideal = 0;
  365.             }
  366.             group->need[u] = ideal - group->member[u];
  367.             for_all_unit_types(u2) {
  368.                 if (could_carry(u2, u)) {
  369.                 ideal = 1;
  370.                 group->need[u2] = ideal - group->member[u2];
  371.                 }
  372.             }
  373.             }
  374.         }
  375.         }
  376.         break;
  377.     case CAPTARGET:
  378.         view = side_view(side, group->x, group->y);
  379.         if (view == EMPTY || view == UNSEEN ||
  380.         allied_side(side, side_n(vside(view)))) {
  381.         disband_group(side, g);
  382.         } else {
  383.         for_all_unit_types(u) {
  384.             if (could_capture(u, group->etype)) {
  385.             ideal = 200 / utypes[u].capture[group->etype];
  386.             group->need[u] = ideal - group->member[u];
  387.             for_all_unit_types(u2) {
  388.                 if (could_carry(u2, u)) {
  389.                 ideal = 1;
  390.                 group->need[u2] = ideal - group->member[u2];
  391.                 }
  392.             }
  393.             }
  394.         }
  395.         }
  396.         break;
  397.     case EXPLORE:
  398.         view = side_view(side, group->x, group->y);
  399.         if (view != UNSEEN)    {
  400.         disband_group(side, g);
  401.         } else {
  402.         for_all_unit_types(u) {
  403.             if (mobile(u)) ideal = 3;
  404.             group->need[u] = ideal - group->member[u];
  405.             for_all_unit_types(u2) {
  406.             if (could_carry(u2, u)) {
  407.                 ideal = 1;
  408.                 group->need[u2] = ideal - group->member[u2];
  409.             }
  410.             }
  411.         }
  412.         }
  413.         break;
  414.     case DEFEND:
  415.         for_all_unit_types(u) {
  416.         ideal = 3;
  417.         group->need[u] = ideal - group->member[u];
  418.         }
  419.         break;
  420.     case OCCUPYHEX:
  421.         /* occupying should only end if no longer a victory condition */
  422.         break;
  423.     default:
  424.         case_panic("group goal", group->goal);
  425.         break;
  426.     }
  427.     }
  428.     for (g = 1; g < MAXGROUPS; ++g) {
  429.     for_all_unit_types(u) {
  430.         plan->demand[u] = group->priority * group->need[u];
  431.     }
  432.     }
  433. }
  434.  
  435. /* Sometimes there is no point in going on, but be careful not to be too */
  436. /* pessimistic.  Right now we only give up if no hope at all. */
  437.  
  438. decide_resignation(side)
  439. Side *side;
  440. {
  441.     int u, u2, sn1, inrunning = FALSE, opposed, own, odds, chance = 0;
  442.     Side *side1, *side2;
  443.     Plan *plan = side_plan(side);
  444.  
  445.     for_all_sides(side1) {
  446.     sn1 = side_number(side1);
  447.     for_all_unit_types(u) {
  448.         plan->allies[sn1][u] = plan->estimate[sn1][u];
  449.         for_all_sides(side2) {
  450.         if (side1 != side2 && allied_side(side1, side2)) {
  451.             plan->allies[sn1][u] +=
  452.             plan->estimate[side_number(side2)][u];
  453.         }
  454.         }
  455.     }
  456.     }
  457.     if (global.numconds == 0) {
  458.     for_all_unit_types(u) {
  459.         own = plan->allies[side_number(side)][u];
  460.         for_all_unit_types(u2) {
  461.         if (could_make(u, u2) && mobile(u2))
  462.             inrunning = TRUE;
  463.         for_all_sides(side1) {
  464.             if (enemy_side(side, side1)) {
  465.             opposed = plan->allies[side_number(side1)][u2];
  466.             if (own > 0 && opposed > 0) {
  467.                 if (could_capture(u, u2) && mobile(u))
  468.                 inrunning = TRUE;
  469.                 if (could_hit(u, u2) && mobile(u))
  470.                 inrunning = TRUE;
  471.             }
  472.             }
  473.         }
  474.         }
  475.     }
  476.     /* should use chance for doubtful situations, like relative strength */
  477.     if (!inrunning || probability(chance)) resign_game(side, NULL);
  478.     } else {
  479.     /* could get pretty complicated... */
  480.     }
  481. }
  482.  
  483. /* When forming a group, first pick out an unused group, then bump a lower */
  484. /* priority group if there's too many.  If it's of lower or equal priority, */
  485. /* then don't form the group at all (failure on equal priorities reduces */
  486. /* fickleness). */
  487.  
  488. form_group(side, goal, priority, x, y, area, etype)
  489. Side *side;
  490. int goal, priority, x, y, area, etype;
  491. {
  492.     int g, u;
  493.     Plan *plan = side_plan(side);
  494.  
  495.     for (g = 1; g < MAXGROUPS; ++g) {
  496.     if (plan->group[g].goal == NOGROUP) break;
  497.     }
  498.     if (g == MAXGROUPS) {
  499.     for (g = 1; g < MAXGROUPS; ++g) {
  500.         if (priority > plan->group[g].priority) {
  501.         disband_group(side, g);
  502.         break;
  503.         }
  504.     }
  505.     }
  506.     if (g < MAXGROUPS) {
  507.     plan->group[g].goal = goal;
  508.     plan->group[g].priority = priority;
  509.     plan->group[g].x = x;
  510.     plan->group[g].y = y;
  511.     plan->group[g].area = area;
  512.     plan->group[g].etype = etype;
  513.     for_all_unit_types(u) {
  514.         plan->group[g].member[u] = 0;
  515.         plan->group[g].need[u] = 0;
  516.     }
  517.     if (Debug) printf("%d: s%d form %s\n", global.time,
  518.               side_number(side), group_desig(plan, g));
  519.     return g;
  520.     } else {
  521.     return 0;
  522.     }
  523. }
  524.  
  525. /* When group's goal accomplished, release the units for other activities. */
  526. /* Not very efficient to scan all units, but simpler and safer than links. */
  527. /* (All units are known to be alive here.) */
  528.  
  529. disband_group(side, g)
  530. Side *side;
  531. int g;
  532. {
  533.     Unit *unit;
  534.     Plan *plan = side_plan(side);
  535.  
  536.     if (Debug) printf("%d: s%d disband %s\n", global.time,
  537.               side_number(side), group_desig(plan, g));
  538.     plan->group[g].goal = NOGROUP;
  539.     plan->group[g].priority = 0;
  540.     for_all_units(unit) {
  541.     if (unit->side == side && unit->group == g) {
  542.         unit->group = NOGROUP;
  543.         unit->goal = NOGOAL;
  544.         if (Debug) printf("%d: %s released from group %d\n",
  545.                   global.time, unit_desig(unit), g);
  546.     }
  547.     }
  548. }
  549.  
  550. /* Given a goal and argument, see if a group already exists like that. */
  551. /* (-1 values serve as unbound variables.) */
  552.  
  553. find_group(side, goal, x, y)
  554. Side *side;
  555. int goal, x, y;
  556. {
  557.     int g;
  558.  
  559.     for (g = 1; g < MAXGROUPS; ++g) {
  560.     if ((side_plan(side)->group[g].goal == goal) &&
  561.         (x == -1 || side_plan(side)->group[g].x == x) &&
  562.         (y == -1 || side_plan(side)->group[g].y == y))
  563.         return g;
  564.     }
  565.     return 0;
  566. }
  567.  
  568. /* Decide whether a change of product is desirable. */
  569.  
  570. change_machine_product(unit)
  571. Unit *unit;
  572. {
  573.     int u = unit->type;
  574.  
  575.     if (Freeze) {
  576.     return FALSE;
  577.     } else if (utypes[u].maker) {
  578.     if (producing(unit)) {
  579.         if ((unit->built > 5) ||
  580.         ((utypes[u].make[unit->product] * unit->built) > 50)) {
  581.         return TRUE;
  582.         }
  583.     } else {
  584.         return TRUE;
  585.     }
  586.     }
  587.     return FALSE;
  588. }
  589.  
  590. /* Machine algorithm for deciding what a unit should build. This routine */
  591. /* must return the type of unit decided upon.  Variety of production is */
  592. /* important, as is favoring types which can leave the builder other than */
  593. /* on a transport.  Capturers of valuable units are also highly preferable. */
  594.  
  595. machine_product(unit)
  596. Unit *unit;
  597. {
  598.     int u = unit->type, u2, type, t, d, x, y, value, bestvalue, besttype, tmp;
  599.     int adjterr[MAXTTYPES];
  600.  
  601.     mside = unit->side;
  602.     for_all_terrain_types(t) adjterr[t] = 0;
  603.     for_all_directions(d) {
  604.     x = wrap(unit->x + dirx[d]);  y = unit->y + diry[d];
  605.     adjterr[terrain_at(x, y)]++;
  606.     }
  607.     besttype = period.firstptype;
  608.     bestvalue = 0;
  609.     tmp = FALSE;
  610.     for_all_unit_types(u2) {
  611.     if (could_make(u, u2)) {
  612.         value = side_plan(mside)->demand[u2];
  613.         if (mobile(u2)) {
  614.         for_all_terrain_types(t) {
  615.             if (could_move(u2, t)) {
  616.             value += adjterr[t] * fraction[t];
  617.             tmp = TRUE;
  618.             }
  619.         }
  620.         }
  621.         if (mside->building[u2] > 0) value /= (mside->building[u2] + 1);
  622.         /* might want to adjust by number of existing units? */
  623.         value = (value * (100 - build_time(unit, u2))) / 100;
  624.         if (tmp && value > bestvalue) {
  625.         besttype = u2;
  626.         bestvalue = value;
  627.         }
  628.     }
  629.     }
  630.     type = besttype;
  631.     /* safety check */
  632.     if (!could_make(unit->type, type)) type = NOTHING;
  633.     if (Debug) printf("%d: %s will now build %s units\n",
  634.               global.time, unit_desig(unit),
  635.               (type == NOTHING ? "no" : utypes[type].name));
  636.     return type;
  637. }
  638.  
  639. /* Decide on and make a move or set orders for a machine player. */
  640.  
  641. machine_move(unit)
  642. Unit *unit;
  643. {
  644.     munit = unit;
  645.     mside = unit->side;
  646.     if (Freeze) {
  647.     order_sentry(unit, 1);
  648.     } else if (humanside(mside)) {
  649.     unit->goal = DRIFT;
  650.     if (maybe_return_home(unit)) return;
  651.     if (probability(50) && short_term(unit)) return;
  652.     search_for_best_move(unit);
  653.     } else {
  654.     if (unit->group == NOGROUP) decide_group(unit);
  655.     if (unit->goal == NOGOAL) decide_goal(unit);
  656.     if (maybe_return_home(unit)) return;
  657.     if (probability(50) && short_term(unit)) return;
  658.     search_for_best_move(unit);
  659.     }
  660. }
  661.  
  662. /* Picking the correct units for a group is essential to its success. */
  663. /* We rate the unit for its suitability for each group based on the needs */
  664. /* of the group and the capabilities and proximity of the unit. */
  665.  
  666. decide_group(unit)
  667. Unit *unit;
  668. {
  669.     int g, u = unit->type, t, suitability, best = 0, bestgroup = 0, dist;
  670.     Plan *plan = side_plan(unit->side);
  671.  
  672.     for (g = 1; g < MAXGROUPS; ++g) {
  673.     suitability = max(0, plan->group[g].need[u]) * plan->group[g].priority;
  674.     switch (plan->group[g].goal) {
  675.     case NOGROUP:
  676.         break;
  677.     case HITTARGET:
  678.     case CAPTARGET:
  679.         dist = distance(unit->x, unit->y,
  680.                 plan->group[g].x, plan->group[g].y);
  681.         suitability -= (suitability * dist) / world.width;
  682.         break;
  683.     case EXPLORE:
  684.         suitability = 1;
  685.         if (!mobile(unit->type)) suitability = -100;
  686.         break;
  687.     case DEFEND:
  688.         suitability = 1;
  689.         break;
  690.     case OCCUPYHEX:
  691.         /* assign a group capable of reaching the hex */
  692.         break;
  693.     default:
  694.         case_panic("group goal", plan->group[g].goal);
  695.         break;
  696.     }
  697.     if (suitability > best) {
  698.         best = suitability;
  699.         bestgroup = g;
  700.     }
  701.     }
  702.     unit->group = bestgroup;
  703.     unit->goal = NOGOAL;
  704.     plan->group[bestgroup].member[unit->type]++;
  705.     if (Debug) printf("%d: %s assigned to %s\n", global.time,
  706.               unit_desig(unit), group_desig(plan, bestgroup));
  707. }
  708.  
  709. /* Set up goals for units that need them. */
  710. /* Goals should differ according to unit's role in group... */
  711.  
  712. decide_goal(unit)
  713. Unit *unit;
  714. {
  715.     int x, y, area;
  716.     Plan *plan = side_plan(unit->side);
  717.  
  718.     x = plan->group[unit->group].x;  y = plan->group[unit->group].y;
  719.     switch (plan->group[unit->group].goal) {
  720.     case NOGOAL:
  721.     /* dubious */
  722.     unit->goal = DRIFT;
  723.     unit->gx = unit->gy = 0;
  724.     break;
  725.     case HITTARGET:
  726.     if (could_hit(unit->type, plan->group[unit->group].etype)) {
  727.         unit->goal = HITTARGET;
  728.     } else if (probability(fullness(unit))) {
  729.         unit->goal = APPROACH;
  730.     } else {
  731.         unit->goal = LOAD;
  732.     }
  733.     unit->gx = x;  unit->gy = y;
  734.     break;
  735.     case CAPTARGET:
  736.     if (could_capture(unit->type, plan->group[unit->group].etype)) {
  737.         unit->goal = CAPTARGET;
  738.     } else if (probability(fullness(unit))) {
  739.         unit->goal = APPROACH;
  740.     } else {
  741.         unit->goal = LOAD;
  742.     }
  743.     unit->gx = x;  unit->gy = y;
  744.     break;
  745.     case EXPLORE:
  746.     unit->goal = APPROACH;
  747.     area = plan->group[unit->group].area;
  748.     unit->gx = x + random(2*area) - area;
  749.     unit->gy = y + random(2*area) - area;
  750.     break;
  751.     case DEFEND:
  752.     unit->goal = DRIFT;
  753.     area = plan->group[unit->group].area;
  754.     unit->gx = x + random(2*area) - area;
  755.     unit->gy = y + random(2*area) - area;
  756.     break;
  757.     case OCCUPYHEX:
  758.     unit->goal = APPROACH;
  759.     unit->gx = x;  unit->gy = y;
  760.     break;
  761.     default:
  762.     case_panic("group goal", plan->group[unit->group].goal);
  763.     break;
  764.     }
  765.     if (Debug) printf("%d: %s in %s gets goal %d->%d,%d\n", global.time,
  766.               unit_desig(unit), group_desig(plan, unit->group),
  767.               unit->goal, unit->gx, unit->gy);
  768. }
  769.  
  770. /* See if the location has a unit that can take us in for refueling */
  771. /* (where's the check for refueling ability?) */
  772.  
  773. haven_p(x, y)
  774. int x, y;
  775. {
  776.     Unit *unit = unit_at(x, y);
  777.  
  778.     return ((unit != NULL && mside == unit->side && alive(unit) &&
  779.          can_carry(unit, munit) && !might_be_captured(unit)));
  780. }
  781.  
  782. /* See if the location has a unit that can repair us */
  783.  
  784. shop_p(x, y)
  785. int x, y;
  786. {
  787.     Unit *unit = unit_at(x, y);
  788.  
  789.     return (unit != NULL && munit->side == unit->side && alive(unit) &&
  790.         can_carry(unit, munit) && could_repair(unit->type, munit->type) &&
  791.         !might_be_captured(unit));
  792. }
  793.  
  794. /* See if we're in a bad way, either on supply or hits, and get to safety */
  795. /* if possible.  If not, then move on to other actions. */
  796. /* Can't be 100% though, there might be some problem preventing move */
  797.  
  798. maybe_return_home(unit)
  799. Unit *unit;
  800. {
  801.     int u = unit->type, ux = unit->x, uy = unit->y, ox, oy, range, success;
  802.  
  803.     if (low_supplies(unit) && probability(98)) {
  804.     range = range_left(unit);
  805.     if (Debug) printf("%s should get supplies - ", unit_desig(unit));
  806.     if ((range * range < numunits) ?
  807.         (search_area(ux, uy, range, haven_p, &ox, &oy)) :
  808.         (find_closest_unit(ux, uy, range, haven_p, &ox, &oy))) {
  809.         order_moveto(unit, ox, oy);
  810.         unit->orders.flags |= SHORTESTPATH;
  811.         unit->orders.flags &=
  812.         ~(ENEMYWAKE|NEUTRALWAKE|SUPPLYWAKE|ATTACKUNIT);
  813.         if (Debug) printf("will resupply at %d,%d\n", ox, oy);
  814.         return TRUE;
  815.     } else {
  816.         if (Debug) printf("but can't\n");
  817.     }
  818.     }
  819.     if (cripple(unit) && probability(98)) {
  820.     /* note that crippled units cannot repair themselves */
  821.     if (Debug) printf("%s badly damaged - ", unit_desig(unit));
  822.     if (unit->transport && could_repair(u, unit->transport->type)) {
  823.         if (Debug) printf("%s will repair\n", unit_desig(unit->transport));
  824.         order_sentry(unit, 1);
  825.         return TRUE;
  826.     } else {
  827.         range = range_left(unit);
  828.         if ((range * range < numunits) ?
  829.         (search_area(ux, uy, range, haven_p, &ox, &oy)) :
  830.         (find_closest_unit(ux, uy, range, shop_p, &ox, &oy))) {
  831.         order_moveto(unit, ox, oy);
  832.         unit->orders.flags &= ~SHORTESTPATH;
  833.         unit->orders.flags &=
  834.             ~(ENEMYWAKE|NEUTRALWAKE|SUPPLYWAKE|ATTACKUNIT);
  835.         if (Debug) printf("will repair at %d,%d\n", ox, oy);
  836.         return TRUE;
  837.         } else {
  838.         if (Debug) printf("but no place to repair\n");
  839.         }
  840.     }
  841.     }
  842.     if (out_of_ammo(unit) >= 0 && probability(80)) {
  843.     if (Debug) printf("%s should reload - ", unit_desig(unit));
  844.     range = range_left(unit);
  845.     if ((range * range < numunits) ?
  846.         (search_area(ux, uy, range, haven_p, &ox, &oy)) :
  847.         (find_closest_unit(ux, uy, range, haven_p, &ox, &oy))) {
  848.         order_moveto(unit, ox, oy);
  849.         unit->orders.flags &= ~SHORTESTPATH;
  850.         unit->orders.flags &= 
  851.         ~(ENEMYWAKE|NEUTRALWAKE|SUPPLYWAKE|ATTACKUNIT);
  852.         if (Debug) printf("will go to %d,%d\n", ox, oy);
  853.         return TRUE;
  854.     } else {
  855.         if (Debug) printf("but can't\n");
  856.     }
  857.     }
  858.     return FALSE;
  859. }
  860.  
  861. /* Return the distance that we can go by shortest path before running out */
  862. /* of important supplies.  Will return at least 1, since we can *always* */
  863. /* move one hex to safety.  This is a worst-case routine, too complicated */
  864. /* to worry about units getting refreshed by terrain or whatever. */
  865.  
  866. range_left(unit)
  867. Unit *unit;
  868. {
  869.     int u = unit->type, r, least = 12345;
  870.  
  871.     for_all_resource_types(r) {
  872.     if (utypes[u].tomove[r] > 0) least = min(least, unit->supply[r]);
  873.     if (utypes[u].consume[r] > 0)
  874.         least = min(least, unit->supply[r] / utypes[u].consume[r]);
  875.     }
  876.     return (least == 12345 ? 1 : least);
  877. }
  878.  
  879. /* Do short-range planning.  Only thing here is intended to be for defenders */
  880. /* protecting a small area (5 moves is arb, should derive from defense */
  881. /* group area). */
  882.  
  883. short_term(unit)
  884. Unit *unit;
  885. {
  886.     int u = unit->type, ux = unit->x, uy = unit->y, range;
  887.  
  888.     switch (unit->goal) {
  889.     case DRIFT:
  890.     range = min(10, 5 * utypes[u].speed);
  891.     if (probability(90)) {
  892.         bestworth = -10000;
  893.         apply_to_area(ux, uy, range, evaluate_hex);
  894.         apply_to_area(ux, uy, range, maximize_worth);
  895.         if (bestworth >= 0) {
  896.         if (Debug) printf("drifting to %d,%d (worth %d)\n",
  897.                   bestx, besty, bestworth);
  898.         order_moveto(unit, bestx, besty);
  899.         unit->orders.flags &= ~SHORTESTPATH;
  900.         return TRUE;
  901.         }
  902.     }
  903.     break;
  904.     case LOAD:
  905.     case APPROACH:
  906.     case HITTARGET:
  907.     case CAPTARGET:
  908.     break;
  909.     default:
  910.         case_panic("unit goal", munit->goal);
  911.     break;
  912.     }
  913.     return FALSE;
  914. }
  915.  
  916. /* Search for most favorable odds anywhere in the area, but only for */
  917. /* the remaining moves in this turn.  Multi-turn tactics is elsewhere. */
  918.  
  919. search_for_best_move(unit)
  920. Unit *unit;
  921. {
  922.     int ux = unit->x, uy = unit->y, range = unit->movesleft, goal;
  923.  
  924.     if (!mobile(unit->type)) {
  925.     order_sentry(unit, 100);
  926.     return;
  927.     }
  928.     if (Debug) printf("%d: %s ", global.time, unit_desig(unit));
  929.     bestworth = -10000;
  930.     apply_to_area(ux, uy, range, evaluate_hex);
  931.     apply_to_area(ux, uy, range, maximize_worth);
  932.     if (bestworth >= 0) {
  933.     if (unit->transport != NULL && mobile(unit->transport->type)) {
  934.         if (Debug) printf("sleeping on transport\n");
  935.         order_sentry(unit, 5);
  936.     } else if ((ux == bestx && uy == besty) || !can_move(unit)) {
  937.         if (Debug) printf("staying put\n");
  938.         order_sentry(unit, 1);
  939.     } else if (probability(90)) {
  940.         if (Debug) printf("moving to %d,%d (worth %d)\n",
  941.                   bestx, besty, bestworth);
  942.         order_moveto(unit, bestx, besty);
  943.         unit->orders.flags &= ~SHORTESTPATH;
  944.     } else {
  945.         if (Debug) printf("hanging around\n");
  946.         order_sentry(unit, random(5));
  947.     }
  948.     } else {
  949.     goal = unit->goal;
  950.     /* jam alternative sometimes... */
  951.     if (probability(95)) goal = DRIFT;
  952.     switch (goal) {
  953.     case DRIFT:
  954.         if (can_produce(unit) && unit->transport == NULL &&
  955.         probability(90)) {
  956.         if (Debug) printf("going to build something\n");
  957.         set_product(unit, machine_product(unit));
  958.         set_schedule(unit);
  959.         order_sentry(unit, unit->schedule+1);
  960.         } else if (probability(90)) {
  961.         if (Debug) printf("going in random direction\n");
  962.         order_movedir(unit, random_dir(), random(3)+1);
  963.         } else {
  964.         if (Debug) printf("hanging around\n");
  965.         order_sentry(unit, random(4)+1);
  966.         }
  967.         break;
  968.     case LOAD:
  969.         if (unit->occupant != NULL) {
  970.         if (Debug) printf("starting off to goal\n");
  971.         unit->goal = APPROACH;
  972.         order_moveto(unit, unit->gx, unit->gy);
  973.         } else {
  974.         if (bestworth >= 0) {
  975.             if (Debug) printf("loading at %d,%d (worth %d)\n",
  976.                       bestworth, bestx, besty);
  977.             order_moveto(unit, bestx, besty);
  978.             unit->orders.flags &= ~SHORTESTPATH;
  979.         } else {
  980.             if (Debug) printf("moving slowly about\n");
  981.             order_movedir(unit, random_dir(), 1);
  982.         }
  983.         }
  984.         break;
  985.     case APPROACH:
  986.     case HITTARGET:
  987.     case CAPTARGET:
  988.         if (unit->transport != NULL) {
  989.         if (unit->transport->group == unit->group) {
  990.             if (Debug) printf("riding in transport\n");
  991.             order_sentry(unit, 4);
  992.         } else if (!can_move(unit)) {
  993.             if (Debug) printf("waiting to get off\n");
  994.             order_sentry(unit, 2);
  995.         } else {
  996.             if (Debug) printf("leaving for %d,%d\n",
  997.                       unit->gx, unit->gy);
  998.             order_moveto(unit, unit->gx, unit->gy);
  999.         }
  1000.         } else {
  1001.         if (Debug) printf("approaching %d,%d\n", unit->gx, unit->gy);
  1002.         order_moveto(unit, unit->gx, unit->gy);
  1003.         }
  1004.         break;
  1005.     default:
  1006.             case_panic("unit goal", munit->goal);
  1007.         break;
  1008.     }
  1009.     }
  1010. }
  1011.  
  1012. /* Given a position nearby the unit, evaluate it with respect to goals, */
  1013. /* general characteristics, and so forth.  -10000 is very bad, 0 is OK, */
  1014. /* 10000 or so is best possible. */
  1015.  
  1016. /* Should downrate hexes within reach of enemy retaliation. */
  1017. /* Should downrate hexes requiring supply consumption to enter/occupy. */
  1018.  
  1019. evaluate_hex(x, y)
  1020. int x, y;
  1021. {
  1022.     bool adjhex, ownhex;
  1023.     int view, etype, dist, worth = 0;
  1024.     int terr = terrain_at(x, y);
  1025.     Side *es;
  1026.     Unit *eunit;
  1027.  
  1028.     view = side_view(mside, x, y);
  1029.     dist = distance(munit->x, munit->y, x, y);
  1030.     adjhex = (dist == 1);
  1031.     ownhex = (dist == 0);
  1032.  
  1033.     if (y <= 0 || y >= world.height-1) {
  1034.     worth = -10000;
  1035.     } else {
  1036.     switch (munit->goal) {
  1037.     case DRIFT:
  1038.         if (ownhex) {
  1039.         worth = -1;
  1040.         } else if (view == UNSEEN) {
  1041.         worth = random(100) / dist;
  1042.         } else if (view == EMPTY) {
  1043.         worth = -100;
  1044.         if (impassable(munit, x, y)) worth -= 900;
  1045.         } else {
  1046.         es = side_n(vside(view));
  1047.         etype = vtype(view);
  1048.         if (es == NULL) {
  1049.             if (could_capture(munit->type, etype)) {
  1050.             worth = 20000 / dist;
  1051.             } else {
  1052.             worth = -10000;
  1053.             }
  1054.         } else if (!allied_side(mside, es)) {
  1055.             worth = 200 + attack_worth(munit, etype);
  1056.             worth += threat(mside, etype, x, y);
  1057.             worth /= dist;
  1058.         } else {
  1059.             worth = 0;
  1060.         }
  1061.         }
  1062.         break;
  1063.     case LOAD:
  1064.         if (ownhex || view == UNSEEN || view == EMPTY) {
  1065.         worth = -1;
  1066.         } else {
  1067.         es = side_n(vside(view));
  1068.         if (mside == es) {
  1069.             if ((eunit = unit_at(x, y)) != NULL) {
  1070.             if (eunit->group == munit->group) {
  1071.                 worth = 4000;
  1072.                 worth /= dist;
  1073.             }
  1074.             }
  1075.         } else {
  1076.             worth = -100;
  1077.         }
  1078.         }
  1079.         break;
  1080.     case APPROACH:
  1081.     case HITTARGET:
  1082.     case CAPTARGET:
  1083.         if (ownhex) {
  1084.         worth = -100;
  1085.         } else if (view == UNSEEN) {
  1086.         worth = random(100) / dist;
  1087.         } else if (view == EMPTY) {
  1088.         if (impassable(munit, x, y)) worth -= 900;
  1089.         } else if (x == munit->gx && y == munit->gy) {
  1090.         worth = 10000;
  1091.         } else {
  1092.         es = side_n(vside(view));
  1093.         etype = vtype(view);
  1094.         if (es == NULL) {
  1095.             if (could_capture(munit->type, etype)) {
  1096.             worth = 20000 / dist;
  1097.             } else {
  1098.             worth = -10000;
  1099.             }
  1100.         } else if (!allied_side(mside, es)) {
  1101.             worth = 200 + attack_worth(munit, etype);
  1102.             worth += threat(mside, etype, x, y);
  1103.             worth /= dist;
  1104.         } else {
  1105.             es = side_n(vside(view));
  1106.             if (mside == es) {
  1107.             if ((eunit = unit_at(x, y)) != NULL) {
  1108.                 if (eunit->group == munit->group &&
  1109.                 eunit->goal == LOAD &&
  1110.                 could_carry(eunit->type, munit->type)) {
  1111.                 worth = 4000;
  1112.                 worth /= dist;
  1113.                 }
  1114.             }
  1115.             } else {
  1116.             worth = -100;
  1117.             }
  1118.         }
  1119.         }
  1120.         break;
  1121.     default:
  1122.         case_panic("unit goal", munit->goal);
  1123.         break;
  1124.     }
  1125.     }
  1126.     if ((munit->gx > 0 || munit->gy > 0) &&
  1127.     (distance(x, y, munit->gx, munit->gy) <
  1128.      distance(munit->x, munit->y, munit->gx, munit->gy))) {
  1129.     worth += 1000;
  1130.     }
  1131.     worth -= 100;
  1132.     worth += utypes[munit->type].productivity[terr];
  1133.     aset(localworth, x, y, worth);
  1134. }
  1135.  
  1136. /* Scan evaluated area looking for best overall hex. */
  1137.  
  1138. maximize_worth(x, y)
  1139. int x, y;
  1140. {
  1141.     int worth;
  1142.  
  1143.     worth = aref(localworth, x, y);
  1144.     if (worth >= 0) {
  1145.     if (worth > bestworth) {
  1146.         bestworth = worth;  bestx = x;  besty = y;
  1147.     } else if (worth == bestworth && flip_coin()) {
  1148.         bestworth = worth;  bestx = x;  besty = y;
  1149.     }
  1150.     }
  1151. }
  1152.  
  1153. /* This is a heuristic estimation of the value of one unit type hitting */
  1154. /* on another.  Should take cost of production into account as well as the */
  1155. /* chance and significance of any effect. */
  1156.  
  1157. attack_worth(unit, etype)
  1158. Unit *unit;
  1159. int etype;
  1160. {
  1161.     int utype = unit->type, worth;
  1162.  
  1163.     worth = bhw[utype][etype];
  1164.     if (utypes[utype].damage[etype] >= utypes[etype].hp)
  1165.     worth *= 2;
  1166.     if (utypes[etype].damage[utype] >= unit->hp)
  1167.     worth /= (could_capture(utype, etype) ? 1 : 4);
  1168.     if (could_capture(utype, etype)) worth *= 4;
  1169.     return worth;
  1170. }
  1171.  
  1172.  
  1173. /* Support functions. */
  1174.  
  1175. /* True if unit is in immediate danger of being captured. */
  1176. /* Needs check on capturer transport being seen. */
  1177.  
  1178. might_be_captured(unit)
  1179. Unit *unit;
  1180. {
  1181.     int d, x, y;
  1182.     Unit *unit2;
  1183.  
  1184.     for_all_directions(d) {
  1185.     x = wrap(unit->x + dirx[d]);  y = unit->y + diry[d];
  1186.     if (((unit2 = unit_at(x, y)) != NULL) &&
  1187.         (enemy_side(unit->side, unit2->side)) &&
  1188.         (could_capture(unit2->type, unit->type))) return TRUE;
  1189.     }
  1190.     return FALSE;
  1191. }
  1192.  
  1193. /* Return true if the given unit type at given position is threatened. */
  1194.  
  1195. threat(side, u, x0, y0)
  1196. Side *side;
  1197. int u, x0, y0;
  1198. {
  1199.     int d, x, y, view, thr = 0;
  1200.     Side *side2;
  1201.  
  1202.     for_all_directions(d) {
  1203.     x = wrap(x0 + dirx[d]);  y = y0 + diry[d];
  1204.     view = side_view(side, x, y);
  1205.     if (view != UNSEEN && view != EMPTY) {
  1206.         side2 = side_n(vside(view));
  1207.         if (allied_side(side, side2)) {
  1208.         if (could_capture(u, vtype(view))) thr += 1000;
  1209.         if (bhw[u][vtype(view)] > 0) thr += 100;
  1210.         }
  1211.     }
  1212.     }
  1213.     return thr;
  1214. }
  1215.  
  1216. /* Test if unit can move out into adjacent hexes. */
  1217.  
  1218. can_move(unit)
  1219. Unit *unit;
  1220. {
  1221.     int d, x, y;
  1222.  
  1223.     for_all_directions(d) {
  1224.     x = wrap(unit->x + dirx[d]);  y = limit(unit->y + diry[d]);
  1225.     if (could_move(unit->type, terrain_at(x, y))) return TRUE;
  1226.     }
  1227.     return FALSE;
  1228. }
  1229.  
  1230. /* Returns the type of missing supplies. */
  1231.  
  1232. out_of_ammo(unit)
  1233. Unit *unit;
  1234. {
  1235.     int u = unit->type, r;
  1236.  
  1237.     for_all_resource_types(r) {
  1238.     if (utypes[u].hitswith[r] > 0 && unit->supply[r] <= 0)
  1239.         return r;
  1240.     }
  1241.     return (-1);
  1242. }
  1243.  
  1244. /* Returns the type of attack to plan for.  (Should balance relative */
  1245. /* effectiveness of each type of attack.) */
  1246.  
  1247. attack_type(e)
  1248. int e;
  1249. {
  1250.     int u;
  1251.  
  1252.     if (utypes[e].surrender > 0 || utypes[e].siege > 0) return BESIEGE;
  1253.     for_all_unit_types(u) if (could_capture(u, e)) return CAPTARGET;
  1254.     return HITTARGET;
  1255. }
  1256.  
  1257. /* True if the given unit is a sort that can build other units. */
  1258.  
  1259. can_produce(unit)
  1260. Unit *unit;
  1261. {
  1262.     int p;
  1263.  
  1264.     for_all_unit_types(p) {
  1265.     if (could_make(unit->type, p)) return TRUE;
  1266.     }
  1267.     return FALSE;
  1268. }
  1269.  
  1270. /* Return percentage of capacity. */
  1271.  
  1272. fullness(unit)
  1273. Unit *unit;
  1274. {
  1275.     int u = unit->type, o, cap = 0, num = 0, vol = 0;
  1276.     Unit *occ;
  1277.  
  1278.     for_all_unit_types(o) cap += utypes[u].capacity[o];
  1279.     for_all_occupants(unit, occ) {
  1280.     num++;
  1281.     vol += utypes[occ->type].volume;
  1282.     }
  1283.     if (utypes[u].holdvolume > 0) {
  1284.     return ((100 * vol) / utypes[u].holdvolume);
  1285.     } else if (cap > 0) {
  1286.     return ((100 * num) / cap);
  1287.     } else {
  1288.     fprintf(stderr, "Fullness ???\n");
  1289.     }
  1290. }
  1291.  
  1292. find_closest_unit(x0, y0, maxdist, pred, rxp, ryp)
  1293. int x0, y0, maxdist, (*pred)(), *rxp, *ryp;
  1294. {
  1295.     Unit *unit;
  1296.  
  1297.     for_all_units(unit) {
  1298.     if (alive(unit) && distance(x0, y0, unit->x, unit->y) <= maxdist) {
  1299.         if ((*pred)(unit->x, unit->y)) {
  1300.         *rxp = unit->x;  *ryp = unit->y;
  1301.         return TRUE;
  1302.         }
  1303.     }
  1304.     }
  1305.     return FALSE;
  1306. }
  1307.